package com.hcj.essearch.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.jsonzou.jmockdata.JMockData;
import com.github.jsonzou.jmockdata.Mocker;
import com.github.jsonzou.jmockdata.TypeReference;
import com.google.gson.Gson;
import com.hcj.essearch.document.ProductDocument;
import com.hcj.essearch.page.Page;
import com.hcj.essearch.service.EsSearchService;
import com.hcj.essearch.utils.IdWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * elasticsearch 搜索
 */
@RestController
public class EsSearchController {
    private static Logger log = LoggerFactory.getLogger(EsSearchController.class);

    @Resource
    private EsSearchService esSearchService;
    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 新增 / 修改索引
     *
     * @return
     */
    @RequestMapping("save")
    public String add(@RequestBody ProductDocument productDocument) {
        esSearchService.save(productDocument);
        return "success";
    }

    /**
     * 删除索引
     *
     * @return
     */
    @RequestMapping("delete/{id}")
    public String delete(@PathVariable String id) {
        esSearchService.delete(id);
        return "success";
    }

    /**
     * 清空索引
     *
     * @return
     */
    @RequestMapping("delete_all")
    public String deleteAll(@PathVariable String id) {
        esSearchService.deleteAll();
        return "success";
    }

    /**
     * 根据ID获取
     *
     * @return
     */
    @RequestMapping("get/{id}")
    public ProductDocument getById(@PathVariable String id) {
        return esSearchService.getById(id);
    }

    /**
     * 根据获取全部
     *
     * @return
     */
    @RequestMapping("get_all")
    public List<ProductDocument> getAll() {
        return esSearchService.getAll();
    }

    /**
     * 搜索
     *
     * @param keyword
     * @return
     */
    @RequestMapping("query/{keyword}")
    public List<ProductDocument> query(@PathVariable String keyword) {
        return esSearchService.query(keyword, ProductDocument.class);
    }

    /**
     * 搜索，命中关键字高亮
     * http://localhost:8088/query_hit?keyword=aa&indexName=orders&fields=productName
     *
     * @param keyword   关键字
     * @param indexName 索引库名称
     * @param fields    搜索字段名称，多个以“，”分割
     * @return
     */
    @RequestMapping("query_hit")
    public List<Map<String, Object>> queryHit(@RequestParam String keyword, @RequestParam String indexName, @RequestParam String fields) {
        String[] fieldNames = {};
        if (fields.contains(",")) fieldNames = fields.split(",");
        else fieldNames[0] = fields;
        return esSearchService.queryHit(keyword, indexName, fieldNames);
    }

    /**
     * 搜索，命中关键字高亮
     * http://localhost:8088/query_hit_page?pageNo=1&pageSize=10&keyword=aa&indexName=orders&fields=productName
     *
     * @param pageNo    当前页
     * @param pageSize  每页显示的数据条数
     * @param keyword   关键字
     * @param indexName 索引库名称
     * @param fields    搜索字段名称，多个以“，”分割
     * @return
     */
    @RequestMapping("query_hit_page")
    public Page<Map<String, Object>> queryHitByPage(@RequestParam int pageNo, @RequestParam int pageSize
            , @RequestParam String keyword, @RequestParam String indexName, @RequestParam String fields) {
        String[] fieldNames = {""};
        if (fields.contains(",")) {
            fieldNames = fields.split(",");
        } else {
            fieldNames[0] = fields;
        }
        return esSearchService.queryHitByPage(pageNo, pageSize, keyword, indexName, fieldNames);
    }

    /**
     * 删除索引库
     *
     * @param indexName
     * @return
     */
    @RequestMapping("delete_index/{indexName}")
    public String deleteIndex(@PathVariable String indexName) {
        esSearchService.deleteIndex(indexName);
        return "success";
    }

    /**
     * 批量模拟100万的数据
     * http://localhost:8088/batchInsert/orders
     * @param indexName
     * @return
     */
    @RequestMapping("batchInsert/{indexName}")
    public String batchInsert(@PathVariable String indexName) {
        long start = System.currentTimeMillis();
        int counter = 0;

        //判断index 是否存在
        if (!elasticsearchTemplate.indexExists(indexName)) {
            elasticsearchTemplate.createIndex(indexName);
        }

        List<IndexQuery> queries = new ArrayList<IndexQuery>();
        List<ProductDocument> productDocuments = this.assembleTestData(1000000);
        if (productDocuments != null && productDocuments.size() > 0) {
            for (ProductDocument productDocument : productDocuments) {
                IndexQuery indexQuery = new IndexQuery();
                indexQuery.setId(productDocument.getId());
                indexQuery.setSource(JSON.toJSONString(productDocument));
                indexQuery.setIndexName(indexName);
                indexQuery.setType("product");
                queries.add(indexQuery);
                //分批提交索引
                if (counter % 4000 == 0) {
                    elasticsearchTemplate.bulkIndex(queries);
                    queries.clear();
                    System.out.println("bulkIndex counter : " + counter);
                }
                counter++;
            }

        }
        //不足批的索引最后不要忘记提交
        if (queries.size() > 0) {
            elasticsearchTemplate.bulkIndex(queries);
        }
        elasticsearchTemplate.refresh(indexName);
        long end = System.currentTimeMillis();
        log.info("整个操作耗时===>:{}", end - start);
        return "success";
    }

    /**
     * 模拟生成数据
     * @param count 数据条数
     * @return
     */
    private static List<ProductDocument> assembleTestData(Integer count) {
        Integer total = count;
        long start = System.currentTimeMillis();
        List<ProductDocument> data = new ArrayList<>(count);
        Long id = IdWorker.getId();
        while (count > 0) {
            ProductDocument p = new ProductDocument(String.valueOf(id + count), JMockData.mock(String.class), JMockData.mock(String.class));
            data.add(p);
            count--;
        }
        long end = System.currentTimeMillis();
        log.info("模拟生成:{}条数据，耗时===>:{}", total, end - start);
        return data;
    }

    public static void main(String[] args) {
        // 生成大批量的数据很慢
        List<ProductDocument> mockDataList = JMockData.mock(new TypeReference<List<ProductDocument>>() {
        });
        log.info("mockDataList:{}", mockDataList);
        log.info("mockDataList.size():{}", mockDataList.size());
        // 耗时4秒生成模拟数据
        assembleTestData(1000000);
    }
}
